Code
pak::pkg_install("ggtree")
pak::pkg_install("ggtreeExtra")
pak::pkg_install("ggstar")
pak::pkg_install("treeio")
pak::pkg_install("ggnewscale")用于系统发育树的 ggtree
Jie Hua
Jun 24, 2025
Jun 24, 2025
系统发育树用于展示不同物种或基因之间的进化关系。R 中的 ggtree 包是可视化这类树的强大工具,支持自定义,也可以与其他类型的数据整合。
Phylogenetic trees are used to show the evolutionary relationships between different species or genes. The ggtree package in R is a powerful tool for visualizing these trees, allowing for customization and integration with other data types.
官方教程:https://bioconductor.org/packages/devel/bioc/vignettes/ggtreeExtra/inst/doc/ggtreeExtra.html
Official tutorial: https://bioconductor.org/packages/devel/bioc/vignettes/ggtreeExtra/inst/doc/ggtreeExtra.html
# Load required packages
library(ggplot2)
library(ggtree)
library(ggtreeExtra)
library(ggstar)
library(treeio)
library(ggnewscale)
# The path of tree file.
trfile <- system.file("extdata", "tree.nwk", package="ggtreeExtra")
# The path of file to plot tip point.
tippoint1 <- system.file("extdata", "tree_tippoint_bar.csv", package="ggtreeExtra")
# The path of first layer outside of tree.
ring1 <- system.file("extdata", "first_ring_discrete.csv", package="ggtreeExtra")
# The path of second layer outside of tree.
ring2 <- system.file("extdata", "second_ring_continuous.csv", package="ggtreeExtra")
# The tree file was imported using read.tree. If you have other tree format files, you can use corresponding functions from treeio package to read it.
tree <- read.tree(trfile)
# This dataset will to be plotted point and bar.
dat1 <- read.csv(tippoint1)
knitr::kable(head(dat1), caption = "Demo tree data 1", format = "pipe")| ID | Location | Length | Group | Abundance |
|---|---|---|---|---|
| DE0655_HCMC_2001 | HK | 0.1786629 | Yes | 12.331055 |
| MS0111_HCMC_1996 | HK | 0.2105236 | Yes | 9.652052 |
| MS0063_HCMC_1995 | HK | 1.4337983 | Yes | 11.584822 |
| DE0490_HCMC_2000 | HK | 0.3823731 | Yes | 7.893231 |
| DE0885_HCMC_2001 | HK | 0.8478901 | Yes | 12.117232 |
| DE0891_HCMC_2001 | HK | 1.5038646 | Yes | 10.819734 |
| ID | Pos | Type |
|---|---|---|
| DE0846_HCMC_2001 | 8 | type2 |
| MS0034_HCMC_1995 | 8 | type2 |
| EG1017_HCMC_2009 | 6 | type2 |
| KH18_HCMC_2009 | 5 | type2 |
| 10365_HCMC_2010 | 7 | type2 |
| EG1021_HCMC_2009 | 1 | type1 |
| ID | Type2 | Alpha |
|---|---|---|
| MS0004_HCMC_1995 | p3 | 0.2256195 |
| DE1150_HCMC_2002 | p2 | 0.2222086 |
| MS0048_HCMC_1995 | p2 | 0.1881510 |
| HUE57_HCMC_2010 | p3 | 0.1939088 |
| DE1486_HCMC_2002 | p2 | 0.2018493 |
| DE1165_HCMC_2002 | p3 | 0.1812997 |
# The format of the datasets is the long shape for ggplot2. If you have short shape dataset,
# you can use `melt` of `reshape2` or `pivot_longer` of `tidyr` to convert it.
# We use ggtree to create fan layout tree.
p <- ggtree(tree, layout="fan", open.angle=10, size=0.5)
#> Scale for y is already present.
#> Adding another scale for y, which will replace the existing scale.
p + theme_blog_overlay## Next, we can use %<+% of ggtree to add annotation dataset to tree.
#p1 <- p %<+% dat1
#p1
## We use geom_star to add point layer outside of tree.
#p2 <- p1 +
# geom_star(
# mapping=aes(fill=Location, size=Length, starshape=Group),
# starstroke=0.2
# ) +
# scale_size_continuous(
# range=c(1, 3),
# guide=guide_legend(
# keywidth=0.5,
# keyheight=0.5,
# override.aes=list(starshape=15),
# order=2)
# ) +
# scale_fill_manual(
# values=c("#F8766D", "#C49A00", "#53B400", "#00C094", "#00B6EB", "#A58AFF", "#FB61D7"),
# guide="none" # don't show the legend.
# ) +
# scale_starshape_manual(
# values=c(1, 15),
# guide=guide_legend(
# keywidth=0.5, # adjust width of legend
# keyheight=0.5, # adjust height of legend
# order=1 # adjust the order of legend for multiple legends.
# ),
# na.translate=FALSE # to remove the NA legend.
# )
#p2
# Or if you don't use %<+% to import annotation dataset, instead of `data` parameter of `geom_fruit`.
# You should specify the column contained tip labels to y axis of `mapping`, here is `y=ID`.
# the `position` parameter was set to `identity` to add the points on the tip nodes.
p2 <- p +
geom_fruit(
data=dat1,
geom=geom_star,
mapping=aes(y=ID, fill=Location, size=Length, starshape=Group),
position="identity",
starstroke=0.2
) +
scale_size_continuous(
range=c(1, 3), # the range of size.
guide=guide_legend(
keywidth=0.5,
keyheight=0.5,
override.aes=list(starshape=15),
order=2
)
) +
scale_fill_manual(
values=c("#F8766D", "#C49A00", "#53B400", "#00C094", "#00B6EB", "#A58AFF", "#FB61D7"),
guide="none"
) +
scale_starshape_manual(
values=c(1, 15),
guide=guide_legend(
keywidth=0.5,
keyheight=0.5,
order=1
)
)
p2 + theme_blog_overlay# Next, we will add a heatmap layer on the outer ring of p2 using `geom_tile` of `ggplot2`.
# Since we want to map some variable of dataset to the `fill` aesthetics of `geom_tile`, but
# the `fill` of p2 had been mapped. So I need use `new_scale_fill` of `ggnewscale` package to initialize it.
p3 <- p2 +
new_scale_fill() +
geom_fruit(
data=dat2,
geom=geom_tile,
mapping=aes(y=ID, x=Pos, fill=Type),
offset=0.08, # The distance between external layers, default is 0.03 times of x range of tree.
pwidth=0.25 # width of the external layer, default is 0.2 times of x range of tree.
) +
scale_fill_manual(
values=c("#339933", "#dfac03"),
guide=guide_legend(keywidth=0.5, keyheight=0.5, order=3)
)
p3 + theme_blog_overlay# You can also add heatmap layer for continuous values.
p4 <- p3 +
new_scale_fill() +
geom_fruit(
data=dat3,
geom=geom_tile,
mapping=aes(y=ID, x=Type2, alpha=Alpha, fill=Type2),
pwidth=0.15,
axis.params=list(
axis="x", # add axis text of the layer.
text.angle=-45, # the text angle of x-axis.
hjust=0 # adjust the horizontal position of text of axis.
)
) +
scale_fill_manual(
values=c("#b22222", "#005500", "#0000be", "#9f1f9f"),
guide=guide_legend(keywidth=0.5, keyheight=0.5, order=4)
) +
scale_alpha_continuous(
range=c(0, 0.4), # the range of alpha
guide=guide_legend(keywidth=0.5, keyheight=0.5, order=5)
)
p4 + theme_blog_overlay# Then add a bar layer outside of the tree.
p5 <- p4 +
new_scale_fill() +
geom_fruit(
data=dat1,
geom=geom_col,
mapping=aes(y=ID, x=Abundance, fill=Location), #The 'Abundance' of 'dat1' will be mapped to x
pwidth=0.4,
axis.params=list(
axis="x", # add axis text of the layer.
text.angle=-45, # the text size of axis.
hjust=0 # adjust the horizontal position of text of axis.
),
grid.params=list() # add the grid line of the external bar plot.
) +
scale_fill_manual(
values=c("#F8766D", "#C49A00", "#53B400", "#00C094", "#00B6EB", "#A58AFF", "#FB61D7"),
guide=guide_legend(keywidth=0.5, keyheight=0.5, order=6)
) +
theme(#legend.position=c(0.96, 0.5), # the position of legend.
legend.background=element_rect(fill=NA), # the background of legend.
legend.title=element_text(size=7), # the title size of legend.
legend.text=element_text(size=6), # the text size of legend.
legend.spacing.y = unit(0.02, "cm") # the distance of legends (y orientation).
)
p5 + theme_blog_overlay# To reproduce.
set.seed(1024)
# generate a tree contained 100 tip labels.
tr <- rtree(100)
# generate three datasets, which are the same except the third column name.
dt <- data.frame(id=tr$tip.label, value=abs(rnorm(100)), group=c(rep("A",50),rep("B",50)))
df <- dt
dtf <- dt
colnames(df)[[3]] <- "group2"
colnames(dtf)[[3]] <- "group3"
# plot tree
p <- ggtree(tr, layout="fan", open.angle=0)
#> Scale for y is already present.
#> Adding another scale for y, which will replace the existing scale.
p + theme_blog_overlay# the second ring
# geom_fruit_list is a list, which first element must be layer of geom_fruit.
p2 <- p1 +
geom_fruit_list(
geom_fruit(
data = df,
geom = geom_col,
mapping = aes(y=id, x=value, fill=group2),
),
scale_fill_manual(values=c("blue", "red")), # To map group2
new_scale_fill(), # To initialize fill scale.
geom_fruit(
data = dt,
geom = geom_star,
mapping = aes(y=id, x=value, fill=group),
size = 2.5,
color = NA,
starstroke = 0
)
) +
new_scale_fill()
p2 + theme_blog_overlay# The third ring
p3 <- p2 +
geom_fruit(
data = dtf,
geom = geom_col,
mapping = aes(y=id, x=value, fill=group3),
stat = "identity"
) +
scale_fill_manual(values=c("#00AED7", "#009E73"))
#> Warning in geom_col(data = structure(list(label = c("t1", "t10", "t100", :
#> Ignoring unknown parameters: `stat`
p3 + theme_blog_overlay